<?php

/**
 * ECSHOP JSON 类
 * ============================================================================
 * 版权所有 (C) 2005-2007 北京亿商互动科技发展有限公司，并保留所有权利。
 * 网站地址: http://www.ecshop.com
 * ----------------------------------------------------------------------------
 * 这是一个免费开源的软件；这意味着您可以在不用于商业目的的前提下对程序代码
 * 进行修改、使用和再发布。
 * ============================================================================
 * @author:     Yan Xuan <xuanyan1983@gmail.com>
 * 修改：dxj 20090723
 * ---------------------------------------------
*/

class Helper_Json
{
	public static $at   = 0;
	public static $ch   = '';
	public static $text = '';

	public function encode($arg)
	{
		if (function_exists('json_encode'))
		{
			return json_encode($arg);
		}

		$returnValue = '';
		$c           = '';
		$i           = '';
		$l           = '';
		$s           = '';
		$v           = '';
		$numeric     = true;

		switch (gettype($arg))
		{
			case 'array':
				foreach ($arg AS $i => $v)
				{
					if (!is_numeric($i))
					{
						$numeric = false;
						break;
					}
				}

				if ($numeric)
				{
					foreach ($arg AS $i => $v)
					{
						if (strlen($s) > 0)
						{
							$s .= ',';
						}
						$s .= self::encode($arg[$i]);
					}

					$returnValue = '[' . $s . ']';
				}
				else
				{
					foreach ($arg AS $i => $v)
					{
						if (strlen($s) > 0)
						{
							$s .= ',';
						}
						$s .= self::encode($i) . ':' . self::encode($arg[$i]);
					}

					$returnValue = '{' . $s . '}';
				}
				break;

			case 'object':
				foreach (get_object_vars($arg) AS $i => $v)
				{
					$v = self::encode($v);

					if (strlen($s) > 0)
					{
						$s .= ',';
					}
					$s .= self::encode($i) . ':' . $v;
				}

				$returnValue = '{' . $s . '}';
				break;

			case 'integer':
			case 'double':
				$returnValue = is_numeric($arg) ? (string) $arg : 'null';
				break;

			case 'string':
				$returnValue = '"' . strtr($arg, array(
				"\r"   => '\\r',    "\n"   => '\\n',    "\t"   => '\\t',     "\b"   => '\\b',
				"\f"   => '\\f',    '\\'   => '\\\\',   '"'    => '\"',
				"\x00" => '\u0000', "\x01" => '\u0001', "\x02" => '\u0002', "\x03" => '\u0003',
				"\x04" => '\u0004', "\x05" => '\u0005', "\x06" => '\u0006', "\x07" => '\u0007',
				"\x08" => '\b',     "\x0b" => '\u000b', "\x0c" => '\f',     "\x0e" => '\u000e',
				"\x0f" => '\u000f', "\x10" => '\u0010', "\x11" => '\u0011', "\x12" => '\u0012',
				"\x13" => '\u0013', "\x14" => '\u0014', "\x15" => '\u0015', "\x16" => '\u0016',
				"\x17" => '\u0017', "\x18" => '\u0018', "\x19" => '\u0019', "\x1a" => '\u001a',
				"\x1b" => '\u001b', "\x1c" => '\u001c', "\x1d" => '\u001d', "\x1e" => '\u001e',
				"\x1f" => '\u001f'
				)) . '"';
				break;

			case 'boolean':
				$returnValue = (string) $arg;
				break;

			default:
				$returnValue = 'null';
		}

		return $returnValue;
	}

	public function decode($text, $assoc = false)
	{
		if (empty($text))
		{
			return '';
		}
		elseif (!is_string($text))
		{
			return false;
		}

		if (function_exists('json_decode'))
		{
			if ($assoc == true) {
				return json_decode($text, TRUE);
			} else {
				return json_decode($text);
			}
		}

		self::$at   = 0;
		self::$ch   = '';
		self::$text = strtr($text, array(
		"\r"   => '', "\n"   => '', "\t"   => '', "\b"   => '',
		"\x00" => '', "\x01" => '', "\x02" => '', "\x03" => '',
		"\x04" => '', "\x05" => '', "\x06" => '', "\x07" => '',
		"\x08" => '', "\x0b" => '', "\x0c" => '', "\x0e" => '',
		"\x0f" => '', "\x10" => '', "\x11" => '', "\x12" => '',
		"\x13" => '', "\x14" => '', "\x15" => '', "\x16" => '',
		"\x17" => '', "\x18" => '', "\x19" => '', "\x1a" => '',
		"\x1b" => '', "\x1c" => '', "\x1d" => '', "\x1e" => '',
		"\x1f" => ''
		));
		self::next();
		if ($assoc == true) {
			return self::std_class_object_to_array(self::val());
		} else {
			return self::val();
		}
	}

	/**
    * triggers a PHP_ERROR
    *
    * @access   private
    * @param    string    $m    error message
    * @return   void
    */
	private function error($m)
	{
		trigger_error($m . ' at offset ' . self::$at . ': ' . self::$text, E_USER_ERROR);
	}

	/**
    * returns the next character of a JSON string
    *
    * @access  private
    * @return  string
    */
	private function next()
	{
		self::$ch = !isset(self::$text{self::$at}) ? '' : self::$text{self::$at};
		self::$at++;

		return self::$ch;
	}

	/**
    * handles strings
    *
    * @access  private
    * @return  void
    */
	private function str()
	{
		$i = '';
		$s = '';
		$t = '';
		$u = '';

		if (self::$ch == '"')
		{
			while (self::next() !== null)
			{
				if (self::$ch == '"')
				{
					self::next();

					return $s;
				}
				elseif (self::$ch == '\\')
				{
					switch (self::next())
					{
						case 'b':
							$s .= '\b';
							break;

						case 'f':
							$s .= '\f';
							break;

						case 'n':
							$s .= '\n';
							break;

						case 'r':
							$s .= '\r';
							break;

						case 't':
							$s .= '\t';
							break;

						case 'u':
							$u = 0;

							for ($i = 0; $i < 4; $i++)
							{
								$t = (integer) sprintf('%01c', hexdec(self::next()));

								if (!is_numeric($t))
								{
									break 2;
								}
								$u = $u * 16 + $t;
							}

							$s .= chr($u);
							break;

						default:
							$s .= self::$ch;
					}
				}
				else
				{
					$s .= self::$ch;
				}
			}
		}

		self::error('Bad string');
	}

	/**
    * handless arrays
    *
    * @access  private
    * @return  void
    */
	private function arr()
	{
		$a = array();

		if (self::$ch == '[')
		{
			self::next();

			if (self::$ch == ']')
			{
				self::next();

				return $a;
			}

			while (isset(self::$ch))
			{
				array_push($a, self::val());

				if (self::$ch == ']')
				{
					self::next();

					return $a;

				}
				elseif (self::$ch != ',')
				{
					break;
				}

				self::next();

			}

			self::error('Bad array');
		}
	}

	/**
    * handles objects
    *
    * @access  public
    * @return  void
    */
	private function obj()
	{
		$k = '';
		$o = new stdClass();

		if (self::$ch == '{')
		{
			self::next();

			if (self::$ch == '}')
			{
				self::next();

				return $o;
			}

			while (self::$ch)
			{
				$k = self::str();

				if (self::$ch != ':')
				{
					break;
				}

				self::next();
				$o->$k = self::val();

				if (self::$ch == '}')
				{
					self::next();

					return $o;
				}
				elseif (self::$ch != ',')
				{
					break;
				}

				self::next();
			}
		}

		self::error('Bad object');
	}

	/**
    * handles objects
    *
    * @access  public
    * @return  void
    */
	private function assoc()
	{
		$k = '';
		$a = array();

		if (self::$ch == '<')
		{
			self::next();

			if (self::$ch == '>')
			{
				self::next();

				return $a;
			}

			while (self::$ch)
			{
				$k = self::str();

				if (self::$ch != ':')
				{
					break;
				}

				self::next();
				$a[$k] = self::val();

				if (self::$ch == '>')
				{
					self::next();

					return $a;
				}
				elseif (self::$ch != ',')
				{
					break;
				}

				self::next();
			}
		}

		self::error('Bad associative array');
	}

	/**
    * handles numbers
    *
    * @access  private
    * @return  void
    */
	private function num()
	{
		$n = '';
		$v = '';

		if (self::$ch == '-')
		{
			$n = '-';
			self::next();
		}

		while (self::$ch >= '0' && self::$ch <= '9')
		{
			$n .= self::$ch;
			self::next();
		}

		if (self::$ch == '.')
		{
			$n .= '.';

			while (self::next() && self::$ch >= '0' && self::$ch <= '9')
			{
				$n .= self::$ch;
			}
		}

		if (self::$ch == 'e' || self::$ch == 'E')
		{
			$n .= 'e';
			self::next();

			if (self::$ch == '-' || self::$ch == '+')
			{
				$n .= self::$ch;
				self::next();
			}

			while (self::$ch >= '0' && self::$ch <= '9')
			{
				$n .= self::$ch;
				self::next();
			}
		}

		$v += $n;

		if (!is_numeric($v))
		{
			self::error('Bad number');
		}
		else
		{
			return $v;
		}
	}

	/**
    * handles words
    *
    * @access  private
    * @return  mixed
    */
	private function word()
	{
		switch (self::$ch)
		{
			case 't':

				if (self::next() == 'r' && self::next() == 'u' && self::next() == 'e')
				{
					self::next();

					return true;
				}
				break;

			case 'f':
				if (self::next() == 'a' && self::next() == 'l' && self::next() == 's' && self::next() == 'e')
				{
					self::next();

					return false;
				}
				break;

			case 'n':
				if (self::next() == 'u' && self::next() == 'l' && self::next() == 'l')
				{
					self::next();

					return null;
				}
				break;
		}

		self::error('Syntax error');
	}

	/**
    * generic value handler
    *
    * @access  private
    * @return  mixed
    */
	private function val()
	{
		switch (self::$ch)
		{
			case '{':
				return self::obj();

			case '[':
				return self::arr();

			case '<':
				return self::assoc();

			case '"':
				return self::str();

			case '-':
				return self::num();

			default:
				return (self::$ch >= '0' && self::$ch <= '9') ? self::num() : self::word();
		}
	}

	private function std_class_object_to_array($stdclassobject)
	{
		$_array = is_object($stdclassobject) ? get_object_vars($stdclassobject) : $stdclassobject;

		foreach ($_array as $key => $value) {
			$value = (is_array($value) || is_object($value)) ? self::std_class_object_to_array($value) : $value;
			$array[$key] = $value;
		}

		return $array;
	}

}

?>